/* typehints:start */
import { Application } from "../application";
/* typehints:end */

import { State } from "./state";
import { APPLICATION_ERROR_OCCURED } from './error_handle'
import { createLogger } from "./utils/logging";
import { removeAllChildren, waitNextFrame } from "./utils/utils";

const logger = createLogger('state');

export class StateManager{
  constructor(app){
    /** @type {Application} */
    this.app = app;
    
    /** @type {State} */
    this.currentState = null;
    this.stateclasses = {};
  }

  /**
   * 注册一个页面状态
   * @param {State} stateClass 
   */
  register(stateClass){
    const dummy = new stateClass;
    assert(dummy instanceof State, '不是一个正确的页面！');
    const key = dummy.getKey();
    assert(!this.stateclasses[key], `页面 ${key} 已经注册过了！`);
    this.stateclasses[key] = stateClass;
  }

  /**
   * 实例化一个页面状态
   * @param {String} key 
   * @returns 
   */
  constructState(key){
    if(this.stateclasses[key]){
      return new this.stateclasses[key]
    }

    assert(false, `页面 ${key} 未注册！`);
  }

  /**
   * 移至指定页面
   * @param {*} key 
   * @param {*} payload 
   */
  moveToState(key, payload = {}){
    if(APPLICATION_ERROR_OCCURED){
      console.warn('程序已崩溃，停止跳转。');
      return;
    }

    // 通知上一个页面执行离开事件
    if(this.currentState){
      if(key === this.currentState.getKey()){
        logger.warn(`<${key}>已经是激活状态。`);
        return;
      }

      this.currentState.internalLeaveCallback();

      // 清除上一个状态的所有引用
      for(const stateKey in this.currentState){
        if(this.currentState.hasOwnProperty(stateKey)){
          delete this.currentState[stateKey]
        }
      }
      this.currentState = null;
    }

    this.currentState = this.constructState(key);
    this.currentState.internalRegisterCallback(this, this.app);

    removeAllChildren(document.body);

    document.body.className = 'gameState ' + (this.currentState.getHasFadeIn() ? "" : 'arrived');
    document.body.id = 'state_' + key;
    document.body.innerHTML = this.currentState.internalGetFullHtml();

    const dialogParent = document.createElement('div')
    dialogParent.classList.add('modalDialogParent');
    document.body.appendChild(dialogParent)

    try{
      this.currentState.internalEnterCallback(payload);
    } catch(err){
      console.log(err);
      throw err;
    }

    this.app.sound.playThemeMusic(this.currentState.getThemeMusic());

    this.currentState.onResized(this.app.screenWidth, this.app.screenHeight);

    window.history.pushState(
      {
        key
      },
      key
    )
    
    waitNextFrame().then(() => {
      document.body.classList.add("arrived");
    })

    return true;
  }
}